package com.ruicar.afs.cloud.basic.sync;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruicar.afs.cloud.basic.common.entity.BasicChannelInfo;
import com.ruicar.afs.cloud.basic.common.entity.BasicMainInfo;
import com.ruicar.afs.cloud.basic.common.entity.BasicMqErrorLog;
import com.ruicar.afs.cloud.basic.common.service.BasicMainInfoService;
import com.ruicar.afs.cloud.basic.common.service.BasicMqErrorLogService;
import com.ruicar.afs.cloud.basic.common.utils.MqSendUtils;
import com.ruicar.afs.cloud.basic.proceeds.mq.dto.ContractMainInfoDTO;
import com.ruicar.afs.cloud.basic.proceeds.mq.sender.CommissionSender;
import com.ruicar.afs.cloud.batch.entity.AfsBatchInfo;
import com.ruicar.afs.cloud.batch.service.AfsBatchInfoService;
import com.ruicar.afs.cloud.bizcommon.voucher.service.VoucherFlowService;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import com.ruicar.afs.cloud.common.modules.constant.VoucherBuriedPointNo;
import com.ruicar.afs.cloud.common.modules.contract.enums.ContractBusinessEnum;
import com.ruicar.afs.cloud.common.modules.contract.enums.MqBusinessTypeEnum;
import com.ruicar.afs.cloud.common.modules.dto.mq.loan.contractdto.LoanActivateReceiveNoticeDTO;
import com.ruicar.afs.cloud.common.modules.dto.mq.voucher.VoucherFlowInfoDto;
import com.ruicar.afs.cloud.common.modules.enums.BusinessType;
import com.ruicar.afs.cloud.common.mq.rabbit.listener.AfsMqBizProcessor;
import com.ruicar.afs.cloud.common.mq.rabbit.message.MqTransCode;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.beans.PropertyDescriptor;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * @author: Lee
 * @date: 2020/5/11 19:39
 * @description: 贷前数据同步
 */
@AllArgsConstructor
@Component
@Slf4j
public class ApplyLoanDataProcessor implements AfsMqBizProcessor<ApplyLoanDataMessage> {

	private final BasicMainInfoService mainInfoService;
	private final CommissionSender commissionSender;
	private final BasicMqErrorLogService mqErrorLogService;
	private final VoucherFlowService voucherFlowService;
	private final AfsBatchInfoService afsBatchInfoService;
	private final ApplyLoanDataChannelSubHandler applyLoanDataChannelSubHandler;
	private final ApplyLoanDataCostSubHandler applyLoanDataCostSubHandler;
	private final ApplyLoanDataCustSubHandler applyLoanDataCustSubHandler;
	private final ApplyLoanDataAssetSubHandler applyLoanDataAssetSubHandler;
	private final MqSendUtils mqSendUtils;

	@Override
	public boolean processMessage(ApplyLoanDataMessage entity) throws Exception {
		AfsBatchInfo afsBatchInfo = afsBatchInfoService.getSystemBatchInfo("icos");
		return SpringContextHolder.getBean(ApplyLoanDataProcessor.class).doRealProcess(entity,afsBatchInfo);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Transactional(rollbackFor = Exception.class)
	public boolean doRealProcess(ApplyLoanDataMessage entity,AfsBatchInfo afsBatchInfo) throws Exception {
		BasicMainInfo mainInfo = new BasicMainInfo();
		try {
			if(entity==null){
				throw new AfsBaseException("MQ消费实体接收类为空，不能激活合同");
			}
			log.info("贷前数据MQ消息: {}", JSON.toJSONString(entity));
			//step1：激活前的公共校验
			applyLoanDataChannelSubHandler.validateOnBefore(afsBatchInfo);

			//step2： 获取当前日结日期
			if(afsBatchInfo==null || StringUtils.isEmpty(afsBatchInfo.getBatchDate())){
				throw new AfsBaseException("获取日结日期失败，不能执行合同激活，请先处理完切日异常后再执行合同激活");
			}
			DateTime batchDate = DateUtil.parse(DateUtil.format(DateUtil.parse(afsBatchInfo.getBatchDate()),"yyyy-MM-dd") +" "+ DateUtil.format(DateUtil.date(), "HH:mm:ss"));
			//step3： 写入合同系统之合同主表
			String existContractNo = applyLoanDataChannelSubHandler.validateOnSaveContractMain(entity);
			if(!StringUtils.isEmpty(existContractNo)) return true;
			mainInfo = applyLoanDataChannelSubHandler.SaveContractMain(entity,batchDate);
			//step4： 写入合同系统之渠道信息
			BasicChannelInfo basicChannelInfo = applyLoanDataChannelSubHandler.saveChannelInfo(entity);
			//step5： 写入合同系统之客户类表
			applyLoanDataCustSubHandler.saveOrUpdateCust(entity);
			//step6： 写入合同系统之资产类表
			applyLoanDataAssetSubHandler.saveOrUpdateAssetInfo(entity);

			//step7： 写入还款计划、摊销计划、收入计划以及付款池处理,返回主产品的ID
			Long mainProductId  = applyLoanDataCostSubHandler.saveAllPlan(entity,batchDate);

			//step8： 更新宽限期
			Integer gracePeriodDays = applyLoanDataCostSubHandler.getGracePeriodDays(String.valueOf(mainProductId),basicChannelInfo.getChannelCity());
			mainInfo.setGracePeriodDays(gracePeriodDays);
			mainInfoService.saveOrUpdate(mainInfo);

			//凭证数据流水数据推送异常
			VoucherFlowInfoDto voucherFlowInfoDto = new VoucherFlowInfoDto();
			voucherFlowInfoDto.setTransNo(mainInfo.getContractNo());
			voucherFlowInfoDto.setContractNo(mainInfo.getContractNo());
			voucherFlowInfoDto.setBuriedPointNo(VoucherBuriedPointNo.contractActivation);// 埋点编号
			voucherFlowInfoDto.setDealerName(mainInfo.getChannelFullName());
			voucherFlowInfoDto.setTransNo(mainInfo.getContractNo());
			voucherFlowInfoDto.setKeepAccountDate(mainInfo.getStartDate());
			voucherFlowInfoDto.setBusinessType((BusinessType) AfsEnumUtil
					.getEnum(AfsEnumUtil.key(mainInfo.getBusinessType()), BusinessType.class));
			voucherFlowService.sendFlow(voucherFlowInfoDto);

			//通过mq向佣金系统发送数据
			JSONObject json = new JSONObject();
			json.put("CamainNo",mainInfo.getApplyNo());//申请单号
			json.put("ContractNo",mainInfo.getContractNo());//合同号
			json.put("CamainId",mainInfo.getId().toString());//合同ID
			commissionSender.sendContractActived(json.toJSONString());
			//通过mq向进件发送合同激活数据
			mqSendUtils.sendApply(mainInfo);
			//通过mq向案件发送合同激活数据
			LoanActivateReceiveNoticeDTO dto = LoanActivateReceiveNoticeDTO.builder()
						.contractNo(mainInfo.getContractNo())
						.caseDate(DateUtil.parse(afsBatchInfo.getBatchDate()))
						.caseType(ContractBusinessEnum.activationSuccess)
						.contractEndDate(mainInfo.getEndDate())
						.build();
				mqSendUtils.contractStatusChange(dto);
		} catch (Exception e) {
			BasicMqErrorLog log = new BasicMqErrorLog();
			ContractMainInfoDTO mainInfoDto = entity.getMainInfo();
			log.setApplyNo(mainInfoDto.getApplyNo());
			log.setContractNo(mainInfoDto.getContractNo());
			log.setMqMessage(JSON.toJSONString(entity));
			log.setErrorMessage(e.getMessage()+e);
			log.setMqBusinessType(MqBusinessTypeEnum.CONT_ACTIVE);
			mqErrorLogService.saveErrorLog(log);
			LoanActivateReceiveNoticeDTO dto = LoanActivateReceiveNoticeDTO.builder()
					.contractNo(mainInfoDto.getContractNo())
					.caseDate(DateUtil.parse(afsBatchInfo.getBatchDate()))
					.caseType(ContractBusinessEnum.activationFail)
					.build();
			mqSendUtils.contractStatusChange(dto);
			throw new Exception(e);
		}
		return true;
	}

	@Override
	public MqTransCode getCode() {
		return MqTransCode.AFS_POS_CASE_CONTRACT_CTM_DATA;
	}
	@Override
	public boolean reQueueOnFail() {
		// TODO Auto-generated method stub
		return false;
	}

	public static Object converBean(Object sourceDto, Class<?> target) {
		if (sourceDto instanceof Collection) {
			return JSONArray.parseArray(JSONObject.toJSONString(sourceDto), target);
		} else {
			return JSONObject.parseObject(JSONObject.toJSONString(sourceDto), target);
		}

	}

	public static String[] getNullpropertyName(Object source) {
		//使用BeanWrapper封装传入的类
		BeanWrapper beanWrapper = new BeanWrapperImpl(source);
		//获取bean类所有的属性定义
		PropertyDescriptor[] pds = beanWrapper.getPropertyDescriptors();
		Set<String> emptyNames = new HashSet<>();
		for(PropertyDescriptor pd : pds) {
			//获取属性值
			Object beanValue = beanWrapper.getPropertyValue(pd.getName());
			if(beanValue == null || StringUtils.isEmpty(beanValue))
				emptyNames.add(pd.getName());
		}
		String [] results = new String[emptyNames.size()];
		return emptyNames.toArray(results);
	}
}
